#include "container.h"

#include <algorithm>
#include <sstream>
#include <iostream>

template<class Key, class Record>
Container<Key, Record>::Container() {}

template<class Key, class Record>
Container<Key, Record>::Container(u_int32_t blockSize) {
    this->size = 0;
    this->maxSize = blockSize - 2;
}

template<class Key, class Record>
Container<Key, Record>::~Container() {
    records.clear();
}

template<class Key, class Record>
u_int32_t Container<Key, Record>::getSizeUsed() const {
    return size;
}

template<class Key, class Record>
u_int32_t Container<Key, Record>::getCapacity() const {
    return maxSize;
}

template<class Key, class Record>
typename std::vector<Record>::iterator Container<Key, Record>::find(Key key, bool strict) {
    //std::cout << "Container::find..." << std::endl;
    for (auto it = records.begin(); it != records.end(); ++it) {
        Record record = *it;

        if ( strict ? record.getKey() == key : record.getKey() > key )
            return it;
    }
    return records.end();
}

template<class Key, class Record>
Nullable<Record> Container<Key, Record>::get(Key key) {
    //std::cout << "Container::get..." << std::endl;
    auto it = find(key, true);
    Nullable<Record> result;
    if (it != records.end())
        result.set(*it);
    return result;
}

template<class Key, class Record>
bool Container<Key, Record>::add(Record record, bool ignoreSize) throw(ContainerFullException) {
    //std::cout << "Container::add..." << std::endl;
    auto it = find(record.getKey(), true);
    if (it != records.end()){
        //std::cout << "Container::add retorno false..." << std::endl;
        return false;
    }

    if (! ignoreSize && BinaryStream::sizeOf(record) + this->size > this->maxSize)
        throw ContainerFullException();

    it = find(record.getKey(), false);
    //std::cout << "records.insert..." << std::endl;
    records.insert(it, record);
    size += BinaryStream::sizeOf(record);

    return true;
}

template<class Key, class Record>
bool Container<Key, Record>::update(Record record) throw(ContainerFullException) {
    return remove(record.getKey()) && add(record);
}

template<class Key, class Record>
bool Container<Key, Record>::remove(Key key) {
    auto it = find(key, true);
    if (it == records.end())
        return false;
    size -= BinaryStream::sizeOf(*it);
    records.erase(it);
    return true;
}

template<class Key, class Record>
std::vector<Record>& Container<Key, Record>::getRecords(){
    return records;
}

template<class Key, class Record>
std::vector<Record> Container<Key, Record>::empty() {
    std::vector<Record> oldRecords = records;
    records.clear();
    this->size = 0;
    return oldRecords;
}

template<class Key, class Record>
void Container<Key, Record>::read(BinaryStream& in) {
    //std::cout << "Read Container..." << std::endl;
    records = in.readVector<Record>();
    //std::cout << "Itero..." << std::endl;
    for (auto it = records.begin(); it != records.end(); ++it)
        size += BinaryStream::sizeOf(*it);
    //std::cout << "Read Container!" << std::endl;
}

template<class Key, class Record>
void Container<Key, Record>::write(BinaryStream& out){
    out.writeVector(records);
}

template<class Key, class Record>
std::string Container<Key, Record>::toString() {
    std::stringstream sout;
    for (auto it = records.begin(); it != records.end(); ++it) {
        sout  << (*it).toString() << " ";
    }
    return sout.str();
}
